/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

package com.huawei.saashousekeeper.dbpool;

import com.huawei.saashousekeeper.dbpool.druid.DruidConfig;

import lombok.Data;
import lombok.extern.log4j.Log4j2;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * 动态数据源配置
 *
 * @author lWX1156935
 * @since 2022/4/22
 */
@Data
@Log4j2
public class PoolConfig {
    private static final String PREFIX = "get";

    /**
     * 全局druid参数配置
     */
    @NestedConfigurationProperty
    protected DruidConfig druidConfig;

    /**
     * 合并配置
     *
     * @param poolConfig 配置
     */
    public void mergeConfig(PoolConfig poolConfig) {
        Optional.ofNullable(poolConfig)
            .ifPresent(item -> {
                // 合并属性
                mergeDruidConfig(poolConfig.getDruidConfig());
            });
    }

    /**
     * 合并druid属性
     *
     * @param superDruidConfig 全局配置
     */
    public void mergeDruidConfig(DruidConfig superDruidConfig) {
        if (superDruidConfig == null && druidConfig == null) {
            return;
        }
        List<String> ignoreProperties = new ArrayList<>();
        Optional.ofNullable(superDruidConfig).ifPresent(item -> {
            Optional.ofNullable(druidConfig).ifPresent(config -> {
                Field[] fields = superDruidConfig.getClass().getDeclaredFields();
                Arrays.stream(fields).forEach(field -> {
                    try {
                        Method method =
                            superDruidConfig.getClass().getMethod(PREFIX + StringUtils.capitalize(field.getName()));
                        Object value = method.invoke(superDruidConfig);
                        Optional.ofNullable(value).ifPresent(v -> {
                            ignoreProperties.add(field.getName());
                        });
                    } catch (NoSuchMethodException e) {
                        log.error("Method {} of DruidConfig not exist," + " {}",
                            PREFIX + StringUtils.capitalize(field.getName()), e);
                        return;
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        log.error("Property {} of DruidConfig Invoke" + " error, {}", field.getName(), e);
                        return;
                    }
                });
            });
        });
        druidConfig = Optional.ofNullable(this.druidConfig).orElse(new DruidConfig());

        Assert.notNull(superDruidConfig, "superDruidConfig is null");
        BeanUtils.copyProperties(superDruidConfig, druidConfig,
            ignoreProperties.toArray(new String[ignoreProperties.size()]));
    }
}
